﻿using System;
using System.Threading;
using System.Windows.Controls;
using MediatorLib;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
using ResourceEnumerator.Inrastructure;
using ResourceEnumerator.UI;

namespace ResourceEnumerator
{
    /// <summary>
    /// Adornment class that draws a square box in the top right hand corner of the viewport
    /// </summary>
    class ResourceEnumerator
    {
        private readonly IWpfTextView _view;
        private readonly IAdornmentLayer _adornmentLayer;
        private readonly Mediator _messenger;
        private readonly EnumeratorView _adornerContent;
        private readonly ITextSearchService _textSearchService;

        /// <summary>
        /// Creates a square image and attaches an event handler to the layout changed event that
        /// adds the the square in the upper right-hand corner of the TextView via the adornment layer
        /// </summary>
        /// <param name="view">The <see cref="IWpfTextView"/> upon which the adornment will be drawn</param>
        /// <param name="textSearchService"></param>
        /// <param name="serviceLocator"></param>
        public ResourceEnumerator(IWpfTextView view, ITextSearchService textSearchService, IServiceLocator serviceLocator)
        {
            _view              = view;
            _messenger         = serviceLocator.Messenger;
            _textSearchService = textSearchService;

            DebugLogger.LogMessage("Before Creating Enumerator View");

            var viewModel = new EnumeratorViewModel(_messenger, serviceLocator.EnumerationService);
            viewModel.ResourceSelected += (sender, args) =>
            {
                var textToFind = args.ResourceKey;
                var snapshotSpan = _textSearchService.FindNext(0, false, new FindData(textToFind, _view.TextSnapshot));
                if (snapshotSpan == null)
                {
                    DebugLogger.LogMessage($"TextSearchService couldn't find {textToFind}");
                    return;
                }
                _view.Caret.MoveTo(snapshotSpan.Value.Start);
                _view.ViewScroller.EnsureSpanVisible(snapshotSpan.Value);
            };

            _adornerContent = new EnumeratorView
            {
                DataContext = viewModel
            };

            _messenger.Register(Messages.AddAdornerContent, (ThreadStart) AddAdornment);
            _messenger.Register(Messages.RemoveAdornerContent, (ThreadStart) RemoveAdornment);

            InvokeParse(_view.TextBuffer.CurrentSnapshot.GetText());

            DebugLogger.LogMessage("After Creating Enumerator View");

            //Grab a reference to the adornment layer that this adornment should be added to
            _adornmentLayer = view.GetAdornmentLayer("Jupiter.ResourceEnumerator");

            _view.ViewportHeightChanged += delegate { OnSizeChange(); };
            _view.ViewportWidthChanged += delegate { OnSizeChange(); };

            _view.TextBuffer.Changed += OnTextBufferChanged;

            AddAdornment();
        }

        bool CurrentlyAdorned { get; set; }

        void OnTextBufferChanged(object sender, TextContentChangedEventArgs textContentChangedEventArgs)
        {
            InvokeParse(textContentChangedEventArgs.After.GetText());
        }

        void InvokeParse(string text)
        {
            ((EnumeratorViewModel) _adornerContent.DataContext).Parse(text);
        }

        void OnSizeChange()
        {
            RemoveAdornment();

            AddAdornment();
        }

        void RemoveAdornment()
        {
            DebugLogger.LogMessage("Before Removing AdornerContent");

            _adornmentLayer.RemoveAdornment(_adornerContent);

            DebugLogger.LogMessage("After Removing AdornerContent");
        }

        void AddAdornment()
        {
            DebugLogger.LogMessage("Before Adding AdornerContent");

            Canvas.SetLeft(_adornerContent, _view.ViewportRight - _adornerContent.ActualWidth);
            Canvas.SetTop(_adornerContent, _view.ViewportTop);

            _adornmentLayer.AddAdornment(
                AdornmentPositioningBehavior.ViewportRelative,
                null, null,
                _adornerContent, null);

            DebugLogger.LogMessage("After Adding AdornerContent");
        }
    }
}
